home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 January: Mac OS SDK / Dev.CD Jan 00 SDK2.toast / What's New / • What was new 11⁄99 / Sample Code / Overview / Optimization TN Demos / CBuffFileStream / CBuffFileStream.c next >
Encoding:
C/C++ Source or Header  |  1999-09-13  |  20.3 KB  |  809 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        CBuffFileStream.c
  3.  
  4.     Contains:    Buffer handling.
  5.  
  6.     Written by:    Tim Carroll
  7.  
  8.     Copyright:    Copyright (c) 1999 Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18. */
  19.  
  20. #include <Errors.h>
  21. #include <Files.h>
  22. #include "FilePermUtils.h"
  23. #include "CBuffFileStream.h"
  24.  
  25. // flush out the buffer we have.
  26. // will write if it is a writing buffer
  27. // otherwise just empty it
  28. static OSErr    BFSFlushOutBuffer(CBuffFileStreamData *fdata);
  29.  
  30. // Check to see if we are changing from read buffering to write
  31. // buffering or vice-versa. If so, flush the buffer.
  32. static OSErr    BFSFlushOnModeSwap(CBuffFileStreamData *fdata,int nowMode);
  33.  
  34. // Trash the buffer. Nasty? Yes. Calling this make you lose data if you
  35. // were in the middle of a buffered write. Don't call it if you don't know
  36. // why you would.
  37. static void        BFSTrashBuffer(CBuffFileStreamData *fdata,int nowMode);
  38.  
  39. // Fill the buffer from the current location in the file. This is used when
  40. // the read buffer runs dry
  41. static OSErr    BFSReadInBuffer(CBuffFileStreamData *fdata);
  42.  
  43. #define DOINGDEBUGCHECKING    0
  44. #define    STOPEACHONENTRY        0
  45.  
  46. #define BYPASSBUFFER        0
  47.  
  48.  
  49. // ---------------------------------------------------------------------------
  50. //        • BFSOpenFIle(CBuffFileStreamData **newdata, FSSpec *inFileInfo, long inPrivileges)
  51. // ---------------------------------------------------------------------------
  52. //    Open a file from an FSSpec
  53. //
  54. //    This opens a file given the specified permissions (fsRdWrPerm, etc.)
  55. //    and creates a file stream buffer record.
  56.  
  57. OSErr    BFSOpenFile(CBuffFileStreamData **newdata, FSSpec *inFileInfo, long inPrivileges)
  58. {
  59.     CBuffFileStreamData     *makeBlock;
  60.     OSErr                    fileErr;
  61.  
  62. #if STOPEACHONENTRY
  63.     Debugger();
  64. #endif
  65.  
  66.     if (0 == *newdata)
  67.         return paramErr;
  68.  
  69. #if DOINGDEBUGCHECKING
  70.     if (0 != ((unsigned long) *newdata & 1))
  71.         return paramErr;
  72. #endif
  73.  
  74.     makeBlock = (CBuffFileStreamData *) NewPtrClear(sizeof(CBuffFileStreamData));
  75.  
  76.     if (0 == makeBlock)
  77.         return MemError();
  78.  
  79.     fileErr = FSpOpenDF(inFileInfo,inPrivileges,&(makeBlock->mFileRefNum));
  80.     if (noErr != fileErr)
  81.     {
  82.         (void) DisposePtr((Ptr) makeBlock);
  83.         *newdata = 0;
  84.  
  85.         return fileErr;
  86.     }
  87.  
  88.     fileErr = GetPermission(makeBlock->mFileRefNum,&(makeBlock->mFilePerms));
  89.     if (noErr != fileErr)
  90.     {
  91.         (void) FSClose(makeBlock->mFileRefNum);
  92.         (void) DisposePtr((Ptr) makeBlock);
  93.         *newdata = 0;
  94.  
  95.         return fileErr;
  96.     }
  97.  
  98.     *newdata = makeBlock;
  99.  
  100.     return noErr;
  101. }
  102.  
  103. // ---------------------------------------------------------------------------
  104. //        • BFSCloseFile(CBuffFileStreamData *fdata)
  105. // ---------------------------------------------------------------------------
  106. //    Close an opened file
  107. //
  108. //    This closes an already opened buffered file.
  109. //    It also deletes the storage associated with the file stream buffer record.
  110.  
  111. OSErr    BFSCloseFile(CBuffFileStreamData *fdata)
  112. {
  113.     OSErr            fileErr;
  114.     OSErr            file2Err;
  115.  
  116. #if STOPEACHONENTRY
  117.     Debugger();
  118. #endif
  119.  
  120. #if DOINGDEBUGCHECKING
  121.     if (0 != ((unsigned long) fdata & 0x1))
  122.         return paramErr;
  123. #endif
  124.  
  125.     if (0 == fdata)
  126.         return paramErr;
  127.  
  128.     fileErr = BFSFlushOutBuffer(fdata);
  129.  
  130.     file2Err = FSClose(fdata->mFileRefNum);
  131.     if (noErr == fileErr)
  132.         fileErr = file2Err;
  133.  
  134.     return fileErr;
  135. }
  136.  
  137. // ---------------------------------------------------------------------------
  138. //        • BFSSetMarker
  139. // ---------------------------------------------------------------------------
  140. //    Place the Read/Write Marker at an offset from a specified position
  141. //
  142. //    fromWhere can be fsAtMark (useless) or fsFromStart, fsFromLEOF, fsFromMark
  143.  
  144. OSErr    BFSSetMarker(CBuffFileStreamData *fdata, long inOffset, long fromWhere)
  145. {
  146.     OSErr            fileErr;
  147.  
  148. #if STOPEACHONENTRY
  149.     Debugger();
  150. #endif
  151.  
  152. #if DOINGDEBUGCHECKING
  153.     if (0 != ((unsigned long) fdata & 0x1))
  154.         return paramErr;
  155. #endif
  156.  
  157.     if (0 == fdata)
  158.         return paramErr;
  159.  
  160.     if (fromWhere < fsAtMark || fromWhere > fsFromMark)
  161.         return paramErr;
  162.  
  163. #if BYPASSBUFFER
  164.     fileErr = SetFPos(fdata->mFileRefNum,fromWhere,inOffset);    
  165. #else
  166. // Flush cache out
  167.     fileErr = BFSFlushOutBuffer(fdata);
  168.     if (noErr != fileErr)
  169.         return fileErr;
  170.  
  171. // Now seek
  172.     fileErr = SetFPos(fdata->mFileRefNum,fromWhere,inOffset);
  173.  
  174. // update where our window starts
  175.     fdata->mWindowLocation = BFSGetMarker(fdata);
  176. #endif
  177.  
  178.     return fileErr;
  179. }
  180.  
  181. long    BFSGetMarker(CBuffFileStreamData *fdata)
  182. {
  183. #if DOINGDEBUGCHECKING
  184.     OSErr            fileErr;
  185. #endif
  186.  
  187. #if STOPEACHONENTRY
  188.     Debugger();
  189. #endif
  190.  
  191. #if DOINGDEBUGCHECKING
  192.     if (0 != ((unsigned long) fdata & 0x1))
  193.         return -1;
  194. #endif
  195.  
  196.     if (0 == fdata)
  197.         return -1;
  198.  
  199. #if BYPASSBUFFER
  200.     {
  201.         Int32            returnMarker;
  202.  
  203.         fileErr = GetFPos(fdata->mFileRefNum,&returnMarker);
  204.         if (noErr != fileErr)
  205.             return -1;
  206.  
  207.         return returnMarker;
  208.     }
  209. #else
  210. #if DOINGDEBUGCHECKING
  211.     {
  212.         long            returnMarker;
  213.  
  214.         fileErr = GetFPos(fdata->mFileRefNum,&returnMarker);
  215.         if (noErr != fileErr)
  216.             return -1;
  217.  
  218.         if (returnMarker != fdata->mWindowLocation)
  219.             DebugStr("\pmarker matching now working.");
  220.     }
  221. #endif
  222.  
  223. // rejigger marker
  224.     return fdata->mWindowLocation + fdata->mBufferCurPos;
  225. #endif
  226. }
  227.  
  228. // ---------------------------------------------------------------------------
  229. //        • BFSSetLength
  230. // ---------------------------------------------------------------------------
  231. //    Set the length, in bytes, of the data fork a buffered file
  232.  
  233. OSErr    BFSSetLength(CBuffFileStreamData *fdata, long inLength)
  234. {
  235. #if STOPEACHONENTRY
  236.     Debugger();
  237. #endif
  238.  
  239. #if DOINGDEBUGCHECKING
  240.     if (0 != ((unsigned long) fdata & 0x1))
  241.         return -1;
  242. #endif
  243.  
  244.     if (0 == fdata)
  245.         return -1;
  246.  
  247. #if BYPASSBUFFER
  248.     return SetEOF(fdata->mFileRefNum,inLength);
  249. #else
  250.     {
  251.         OSErr                fileErr;
  252.  
  253.         fileErr = BFSFlushOutBuffer(fdata);
  254.         if (noErr != fileErr)
  255.             return fileErr;
  256.  
  257.     // If we get an error, continue so we keep an accurate marker
  258.         fileErr = SetEOF(fdata->mFileRefNum,inLength);
  259.  
  260.         fdata->mWindowLocation = BFSGetMarker(fdata);
  261.  
  262.         return fileErr;
  263.     }
  264. #endif
  265. }
  266.  
  267. // ---------------------------------------------------------------------------
  268. //        • BFSGetLength
  269. // ---------------------------------------------------------------------------
  270. //    Return the length, in bytes, of the data fork of a buffered file
  271.  
  272. long    BFSGetLength(CBuffFileStreamData *fdata)
  273. {
  274.     OSErr                fileErr;
  275.  
  276. #if STOPEACHONENTRY
  277.     Debugger();
  278. #endif
  279.  
  280. #if DOINGDEBUGCHECKING
  281.     if (0 != ((unsigned long) fdata & 0x1))
  282.         return -1;
  283. #endif
  284.  
  285.     if (0 == fdata)
  286.         return -1;
  287.  
  288. #if BYPASSBUFFER
  289.     {
  290.         Int32                returnLength;
  291.  
  292.     // Find file system length
  293.         fileErr = GetEOF(fdata->mFileRefNum,&returnLength);
  294.         if (noErr != fileErr)
  295.             return -1;
  296.  
  297.         return returnLength;
  298.     }
  299. #else
  300.     {
  301.         long                returnLength;
  302.         long                markerPos;
  303.  
  304.     // Find file system length
  305.         fileErr = GetEOF(fdata->mFileRefNum,&returnLength);
  306.         if (noErr != fileErr)
  307.             return -1;
  308.  
  309.     // adjust length in case buffer passes current end of file
  310.         markerPos = BFSGetMarker(fdata);
  311.         if (-1 != markerPos && markerPos > returnLength)
  312.             returnLength = markerPos;
  313.  
  314.         return returnLength;
  315.     }
  316. #endif
  317. }
  318.  
  319. // ---------------------------------------------------------------------------
  320. //        • BFSWrite
  321. // ---------------------------------------------------------------------------
  322. //    Write data from a buffer to a buffered file stream
  323. //
  324. //    Returns an error code and passes back the number of bytes actually
  325. //    written, which may be less than the number requested if an error occurred.
  326. //    If no error is returned, the full amount was written.
  327.  
  328. OSErr    BFSWrite(CBuffFileStreamData *fdata, long *writeAmt, const void *inBuffer)
  329. {
  330. #if STOPEACHONENTRY
  331.     Debugger();
  332. #endif
  333.  
  334. #if DOINGDEBUGCHECKING
  335.     if (0 != ((unsigned long) fdata & 0x1) || 0 != ((unsigned long) writeAmt & 0x1))
  336.         return paramErr;
  337. #endif
  338.  
  339.     if (0 == fdata || 0 == writeAmt || *writeAmt < 0)
  340.         return paramErr;
  341.  
  342. #if BYPASSBUFFER
  343.     return FSWrite(fdata->mfRefNum,writeAmt,inBuffer);
  344. #else
  345.     {
  346.         const void    *subBuffer = inBuffer;
  347.         long        remainByteCount = *writeAmt;
  348.         OSErr        modeErr;
  349.         long        freeBytes;
  350.  
  351.     //
  352.     // Road map: here's what we are doing
  353.     //
  354.     // 1st: Check to see if we have write permissions
  355.     // 2nd: Is our data less the remaining section of the buffer plus an empty buffer?
  356.     //     Yes: 3rd: put as much data as you can in the current buffer
  357.     //          4th: flush the buffer if full
  358.     //          5th: put the rest of the data in the buffer
  359.     //      No: 3rd: Is there data already in the buffer?
  360.     //              Yes: 4th: put as much data as you can in the current buffer
  361.     //                   5th: flush the buffer
  362.     //               No: 6th: bypass the buffer to write the rest
  363.     //
  364.  
  365.  
  366.     // We only allow writing to the end of the buffer.
  367.     // This is okay since any seeks flush the buffer and begin with a fresh one.
  368.     // We keep mBufferCurPos in sync with mBufferLength though to make some
  369.     // operations easier.
  370.  
  371.     // check for write permissions
  372.         if (fsRdPerm == fdata->mFilePerms ||
  373.             fsRdWrShPerm == fdata->mFilePerms)
  374.         {
  375.             return opWrErr;        // no write permissions
  376.         }
  377.  
  378.     // Check to see if we changed modes from read to write
  379.         modeErr = BFSFlushOnModeSwap(fdata,eBuffFileStreamIamWriting);
  380.         if (noErr != modeErr)
  381.             return modeErr;
  382.  
  383.         freeBytes = eBuffFileStreamBufferMaxSize - fdata->mBufferLength;
  384.  
  385.     // Can we write by using the available space plus another buffer?
  386.         if (remainByteCount < (freeBytes + eBuffFileStreamBufferMaxSize))
  387.         {
  388.             long                addBytes = freeBytes;
  389.  
  390.         // Take the lesser number of the available space or the bytes we have
  391.             if (remainByteCount < addBytes)
  392.                 addBytes = remainByteCount;
  393.  
  394.         // Move in the data
  395.             BlockMoveData(subBuffer,&(fdata->mFileWindow[fdata->mBufferLength]),addBytes);
  396.  
  397.         // Adjust the buffer pointer, source pointer, and bytes left to write
  398.             fdata->mBufferLength += addBytes;
  399.             fdata->mBufferCurPos += addBytes;
  400.             subBuffer = (const void *) ((char *) subBuffer + addBytes);
  401.             remainByteCount -= addBytes;
  402.  
  403.         // Now flush the buffer if it is full
  404.             if (eBuffFileStreamBufferMaxSize == fdata->mBufferLength)
  405.             {
  406.                 OSErr flushErr = BFSFlushOutBuffer(fdata);
  407.  
  408.                 if (flushErr != noErr)
  409.                     return flushErr;
  410.             }
  411.  
  412.         // Now, do we have more data to write? If so, put it in the buffer
  413.             if (remainByteCount > 0)
  414.             {
  415.             // Move in the data
  416.                 BlockMoveData(subBuffer,fdata->mFileWindow,remainByteCount);
  417.  
  418.             // Adjust the buffer pointer
  419.                 fdata->mBufferLength = remainByteCount;
  420.                 fdata->mBufferCurPos = remainByteCount;
  421.             }
  422.         }
  423.         else
  424.         {
  425.         // We have so much data we are going to at least partially bypass the buffer.
  426.         // First, if we have a partial buffer, we should put as much of our data as
  427.         // possible into the buffer before we write the rest as a bypass.
  428.         // If we don't have a partial buffer, then we would be turning one write
  429.         // into two, and we don't want that, so skip this step and write it all
  430.         // as a bypass.
  431.             if (fdata->mBufferLength > 0)
  432.             {
  433.                 OSErr flushErr;
  434.  
  435.             // Take as much data as we can
  436.                 BlockMoveData(subBuffer,&(fdata->mFileWindow[fdata->mBufferLength]),freeBytes);
  437.  
  438.             // Adjust the buffer pointer, source pointer, and bytes left to write
  439.                 fdata->mBufferLength = eBuffFileStreamBufferMaxSize;
  440.                 fdata->mBufferCurPos = eBuffFileStreamBufferMaxSize;
  441.                 subBuffer = (const void *) ((char *) subBuffer + freeBytes);
  442.                 remainByteCount -= freeBytes;
  443.  
  444.             // Now flush this full buffer
  445.                 flushErr = BFSFlushOutBuffer(fdata);
  446.  
  447.                 if (flushErr != noErr)
  448.                     return flushErr;
  449.             }
  450.  
  451.         // Now we are going to write the rest as a bypass
  452.             {
  453.                 long            writeCount = remainByteCount;
  454.                 OSErr            bypassErr = FSWrite(fdata->mFileRefNum,&writeCount,subBuffer);
  455.  
  456.                 if (bypassErr)
  457.                     return bypassErr;
  458.             }
  459.         }
  460.  
  461.     // We've written all we have, and we have a empty buffer (because it was
  462.     // empty, or we flushed it), we are ready for further writes
  463.     }
  464.  
  465.     *writeAmt = 0;
  466.  
  467.     return noErr;
  468. #endif    // !BYPASSBUFFER
  469. }
  470.  
  471. // ---------------------------------------------------------------------------
  472. //        • BFSRead
  473. // ---------------------------------------------------------------------------
  474. //    Read data from a buffered data stream to a buffer
  475. //
  476. //    Returns an error code and passes back the number of bytes actually
  477. //    read, which may be less than the number requested if an error occurred.
  478. //    If no error is returned, the full amount was read.
  479.  
  480. OSErr    BFSRead(CBuffFileStreamData *fdata, long *readAmt, void *outBuffer)
  481. {
  482. #if STOPEACHONENTRY
  483.     Debugger();
  484. #endif
  485.  
  486. #if DOINGDEBUGCHECKING
  487.     if (0 != ((unsigned long) fdata & 0x1) || 0 != ((unsigned long) readAmt & 0x1))
  488.         return paramErr;
  489. #endif
  490.  
  491.     if (0 == fdata || 0 == readAmt || *readAmt < 0)
  492.         return paramErr;
  493.  
  494. #if BYPASSBUFFER
  495.     return FSRead(fdata->mfRefNum,writeAmt,inBuffer);
  496. #else
  497.     {
  498.         void    *subBuffer             = outBuffer;
  499.         long    remainByteCount     = *readAmt;
  500.         long    gotBytes             = fdata->mBufferLength - fdata->mBufferCurPos;
  501.  
  502.     //
  503.     // Road map: here's what we are doing
  504.     //
  505.     // 1st: Is our request less than the remaining data in the buffer plus another buffer?
  506.     //     Yes: 2nd: get as much data as you can/need from the current buffer
  507.     //          3rd: need more?
  508.     //          Yes: 4th: refill buffer
  509.     //               5th: read the rest of the data from the buffer (or eof)
  510.     //      No: 2nd: Is there data already in the buffer?
  511.     //          3rd: get what you can from the buffer
  512.     //          4th: bypass to read the rest
  513.     //
  514.  
  515.     // Check to see if we changed modes from write to read
  516.         OSErr modeErr = BFSFlushOnModeSwap(fdata,eBuffFileStreamIamReading);
  517.  
  518.         if (noErr != modeErr)
  519.         {
  520.             *readAmt = 0;
  521.             return modeErr;
  522.         }
  523.  
  524.     // See if we could possibly satisfy the request from the current buffer contents
  525.     // and another less than full buffer?
  526.  
  527.         if (*readAmt < (gotBytes + eBuffFileStreamBufferMaxSize))
  528.         {
  529.         // Yes, so we want to use up what we have, read a whole buffer and
  530.         // use part of this. However, this is written as a while loop to handle
  531.         // operations at the end of a file.
  532.  
  533.             while (remainByteCount > 0)
  534.             {
  535.                 long            addBytes;
  536.  
  537.             // Is the buffer empty and we still need more?
  538.                 if (remainByteCount > 0 && fdata->mBufferCurPos == fdata->mBufferLength)
  539.                 {
  540.                 // Yes, refill it
  541.                     OSErr            fillErr = BFSReadInBuffer(fdata);
  542.  
  543.                     if (noErr != fillErr)
  544.                     {
  545.                     //    Probably an eof, we ran out of data.
  546.                         if (fillErr == eofErr)
  547.                             *readAmt -= remainByteCount;
  548.                         else
  549.                             *readAmt = 0;
  550.  
  551.                         return fillErr;
  552.                     }
  553.                 }
  554.  
  555.                 addBytes = fdata->mBufferLength - fdata->mBufferCurPos;
  556.  
  557.             // Take the lesser number of the available data or the bytes we want
  558.                 if (remainByteCount < addBytes)
  559.                     addBytes = remainByteCount;
  560.  
  561.             // Move in the data
  562.                 BlockMoveData(&(fdata->mFileWindow[fdata->mBufferCurPos]),subBuffer,addBytes);
  563.  
  564.             // Adjust location in buffer, destination pointer, and bytes left to read
  565.                 fdata->mBufferCurPos += addBytes;
  566.                 subBuffer = (void *) ((char *) subBuffer + addBytes);
  567.                 remainByteCount -= addBytes;
  568.  
  569.             // Is the buffer empty and we still need more?
  570.                 if (remainByteCount > 0 && fdata->mBufferCurPos == fdata->mBufferLength)
  571.                 {
  572.                 // Yes, refill it
  573.                     OSErr        fillErr = BFSReadInBuffer(fdata);
  574.  
  575.                     if (fillErr)
  576.                     {
  577.                     //    Probably an eof, we ran out of data.
  578.                         if (fillErr == eofErr)
  579.                             *readAmt -= remainByteCount;
  580.                         else
  581.                             *readAmt = 0;
  582.  
  583.                         return fillErr;
  584.                     }
  585.                 }
  586.             }
  587.         }
  588.         else
  589.         {
  590.         // Fast-track big read, use data available in the buffer, then switch
  591.         // to big dedicated reads.
  592.             long            readAttempt;
  593.             OSErr            bypassErr;
  594.  
  595.             if (gotBytes > 0)        // use the data already in the buffer
  596.             {
  597.             // Move in the data
  598.                 BlockMoveData(&(fdata->mFileWindow[fdata->mBufferCurPos]),subBuffer,gotBytes);
  599.  
  600.             // Adjust location in buffer, destination pointer, and bytes left to read
  601.                 fdata->mBufferCurPos += gotBytes;
  602.                 subBuffer = (void *) ((char *) subBuffer + gotBytes);
  603.                 remainByteCount -= gotBytes;
  604.             }
  605.  
  606.             readAttempt = remainByteCount;
  607.  
  608.             bypassErr = FSRead(fdata->mFileRefNum,&readAttempt,subBuffer);
  609.             if (bypassErr)
  610.             {
  611.                 if (bypassErr == eofErr)
  612.                 {
  613.                     remainByteCount -= readAttempt;
  614.                     *readAmt -= remainByteCount;
  615.  
  616.                     return bypassErr;
  617.                 }
  618.                 *readAmt = 0;
  619.                 return bypassErr;
  620.             }
  621.  
  622.             remainByteCount -= readAttempt;
  623.         }
  624.  
  625.         *readAmt -= remainByteCount;
  626.  
  627.         return noErr;
  628.     }
  629. #endif
  630. }
  631.  
  632. // ---------------------------------------------------------------------------
  633. //        • BFSGetFilePermissions
  634. // ---------------------------------------------------------------------------
  635. //    Find the permissions acquired when opening a buffered data file.
  636. //
  637. //    This is useful if you specified fsCurPerm on open and want to know what
  638. //    permissions you got.
  639.  
  640. long    BFSGetFilePermissions(CBuffFileStreamData *fdata)
  641. {
  642. #if STOPEACHONENTRY
  643.     SysBreak();
  644. #endif
  645.  
  646. #if DOINGDEBUGCHECKING
  647.     if (0 != ((unsigned long) fdata & 0x1))
  648.         return paramErr;
  649. #endif
  650.  
  651.     if (0 == fdata)
  652.         return paramErr;
  653.  
  654.     return fdata->mFilePerms;
  655. }
  656.  
  657. // ---------------------------------------------------------------------------
  658. //        • BFSFlushFile
  659. // ---------------------------------------------------------------------------
  660. //    Find the permissions acquired when opening a buffered data file.
  661. //
  662. //    This is useful if you specified fsCurPerm on open and want to know what
  663. //    permissions you got.
  664.  
  665. OSErr    BFSFlushFile(CBuffFileStreamData *fdata)
  666. {
  667. #if STOPEACHONENTRY
  668.     SysBreak();
  669. #endif
  670.  
  671. #if DOINGDEBUGCHECKING
  672.     if (0 != ((unsigned long) fdata & 0x1))
  673.         return paramErr;
  674. #endif
  675.  
  676.     if (0 == fdata)
  677.         return paramErr;
  678.  
  679. #if BYPASSBUFFER
  680.     return noErr;
  681. #else
  682.     {
  683.         OSErr            flushErr;
  684.  
  685.         flushErr = BFSFlushOutBuffer(fdata);
  686.  
  687.     // You should do a MacOS flush file here.
  688.     // I'm not going to.
  689.  
  690.         return flushErr;
  691.     }
  692. #endif
  693. }
  694.  
  695. // flush out the buffer we have.
  696. // will write if it is a writing buffer
  697. // otherwise just empty it
  698. // This is not an externally accessible function so it does NOT
  699. // check its parameters.
  700. OSErr    BFSFlushOutBuffer(CBuffFileStreamData *fdata)
  701. {
  702. #if BYPASSBUFFER
  703.     return noErr;
  704. #else
  705.     OSErr            returnValue = noErr;
  706.  
  707.     if (eBuffFileStreamIamWriting == fdata->mBufferMode)
  708.     {
  709.         long            writeAmount = fdata->mBufferLength;
  710.  
  711.     // write the data and update the file position
  712.         returnValue = FSWrite(fdata->mFileRefNum,&writeAmount,fdata->mFileWindow);
  713.  
  714.     // update kept file position
  715.         fdata->mWindowLocation += fdata->mBufferCurPos;
  716.         fdata->mBufferLength = 0;
  717.         fdata->mBufferCurPos = 0;
  718.     }
  719.     else
  720.     {
  721.     // update kept file position
  722.         fdata->mWindowLocation += fdata->mBufferCurPos;
  723.  
  724.         SetFPos(fdata->mFileRefNum,fsFromStart,fdata->mWindowLocation);
  725.  
  726.         fdata->mBufferLength = 0;
  727.         fdata->mBufferCurPos = 0;
  728.     }
  729.  
  730.     return returnValue;
  731. #endif
  732. }
  733.  
  734. // Check to see if we are changing from read buffering to write
  735. // buffering or vice-versa. If so, flush the buffer.
  736. // This is not an externally accessible function so it does NOT
  737. // check its parameters.
  738. OSErr    BFSFlushOnModeSwap(CBuffFileStreamData *fdata,int nowMode)
  739. {
  740. #if BYPASSBUFFER
  741.     return noErr;
  742. #else
  743.     OSErr        flushErr = noErr;
  744.  
  745.     if ((fdata->mBufferLength > 0) && (fdata->mBufferMode != nowMode))
  746.     {
  747.         flushErr = BFSFlushOutBuffer(fdata);
  748.  
  749.         fdata->mBufferLength = 0;        // flush FOR SURE (sorry)
  750.         fdata->mBufferCurPos = 0;
  751.     }
  752.  
  753. // set buffer mode
  754.     fdata->mBufferMode = nowMode;
  755.  
  756.     return flushErr;
  757. #endif
  758. }
  759.  
  760. // Trash the buffer. Nasty? Yes. Calling this make you lose data if you
  761. // were in the middle of a buffered write. Don't call it if you don't know
  762. // why you would.
  763. // This is not an externally accessible function so it does NOT
  764. // check its parameters.
  765. void        BFSTrashBuffer(CBuffFileStreamData *fdata,int nowMode)
  766. {
  767. #if BYPASSBUFFER
  768. #else
  769. // delete the data in the buffer
  770.     fdata->mBufferLength = 0;
  771.     fdata->mBufferCurPos = 0;
  772.  
  773. // set the buffer mode
  774.     fdata->mBufferMode = nowMode;
  775. #endif
  776. }
  777.  
  778. // Fill the buffer from the current location in the file. This is used when
  779. // the read buffer runs dry
  780. // This is not an externally accessible function so it does NOT
  781. // check its parameters.
  782. OSErr    BFSReadInBuffer(CBuffFileStreamData *fdata)
  783. {
  784.     OSErr            returnValue = noErr;
  785.     long            readAmount = eBuffFileStreamBufferMaxSize;
  786.  
  787. #if BYPASSBUFFER
  788.     return noErr;
  789. #else
  790. #if DOINGDEBUGCHECKING
  791.     if (eBuffFileStreamIamReading != fdata->mBufferMode)
  792.     {
  793.         DebugStr("\pTried to fill the buffer in write mode!");
  794.     }
  795. #endif
  796.     fdata->mWindowLocation += fdata->mBufferCurPos;        // jump down the file some
  797.  
  798.     returnValue = FSRead(fdata->mFileRefNum,&readAmount,fdata->mFileWindow);
  799.  
  800.     if (eofErr == returnValue && 0 != readAmount)
  801.         returnValue = noErr;            // ignore under reads unless we run dry
  802.  
  803.     fdata->mBufferLength = readAmount;
  804.     fdata->mBufferCurPos = 0;
  805.  
  806.     return returnValue;
  807. #endif
  808. }
  809.